ShortKey.Header = { Item = nil }

local Header = ShortKey.Header
local CustomButton = ShortKey.CustomButton
local UserConfig = ShortKey.UserConfig
local InnerConfig = ShortKey.InnerConfig
local NILCONDITION = ShortKey.NILCONDITION

------------------------------------------------------------------------------------------------------
--local functions
------------------------------------------------------------------------------------------------------
-- nil, empty, not string type will return true
local function IsStringEmpty(text)
	if (text == nil or text == "" or type(text) ~= "string") then
		return true
	end
	return false
end

local function GetButtonObject(buttonname)
	local button = getglobal(buttonname)

	if (button) then
		local objtype = button:GetObjectType()
		if (objtype == "Button" or objtype == "CheckButton") then
			return button
		end
	end
end

local function debug(frame, ...)
	for i = 1, select("#", ...) do
		local val = select(i, ...) or "nil"
		print (i.."    "..val)
	end
	print("---------------------------")
end

------------------------------------------------------------------------------------------------------
--Override Function
------------------------------------------------------------------------------------------------------

function ShortKey.ErrorReport(innerconfigitem, configitem, msg)
	print("ShortKey config error: "..msg)

	if (innerconfigitem) then
		print(string.format("src item: [%s]", UserConfig:ToString(innerconfigitem)))
	end

	if (configitem) then
		print(string.format("dst item: [%s]", UserConfig:ToString(configitem)))
	end
end

function CustomButton:Create()
	local index = table.getn(self.Items) + 1
	local buttonname = "ShortKeyActionButton"..index
	CreateFrame("Button", buttonname, UIParent, "SecureActionButtonTemplate")
	table.insert(self.Items, buttonname)
	return buttonname
end

function UserConfig:IsGroupLoad(group)
	if (not IsStringEmpty(group.Class) and group.Class ~= UnitClass("player")) then
		return false
	elseif (not IsStringEmpty(group.Character) and group.Character ~= UnitName("player")) then
		return false
	elseif (not IsStringEmpty(group.Race) and group.Race ~= UnitRace("player")) then
		return false
	elseif (group.Talent and tonumber(group.Talent) ~= GetActiveTalentGroup()) then
		return false
	end

	return true
end

local ErrorReport = ShortKey.ErrorReport

------------------------------------------------------------------------------------------------------
--Header
------------------------------------------------------------------------------------------------------

function Header:Create()
	self.Item = CreateFrame("Frame", "ShortKeyHeaderFrame", nil, "SecureHandlerStateTemplate");
	self.Item:SetAttribute("BindButton", self.BindButton)
	self.Item:SetAttribute("UnBindButton", self.UnBindButton)

	--non secure environment
	self.Item.AddWatch = function (header, buttonname, conds)
		header:SetAttribute("_onstate-"..buttonname, [[control:RunAttribute("BindButton", stateid, newstate)]])
		RegisterStateDriver(header, buttonname, conds)
	end

	self.Item.debug = debug
	return self.Item
end

function Header:Execute()
	self.Item:Execute(self.Bind)
end

function Header:Fill()
	local index = 0
	self.Item:SetAttribute("NILCONDITION", NILCONDITION)

	for buttonname, _ in pairs(InnerConfig.Items) do
		local button = GetButtonObject(buttonname)

		if (button) then
			index = index + 1
			self.Item:SetFrameRef(buttonname, button)
			self.Item:SetAttribute("button"..index, buttonname)
			self:FillButton(button)
		else
			ErrorReport(nil, nil, "Button not exist or not a Button or CheckButton type: "..buttonname)
		end
	end
end

function Header:FillButton(button)
	local frameitem = InnerConfig.Items[button:GetName()]
	local needcond = ( table.getn(frameitem.ConditionSequence) > 0 )
	local conds = ""

	button:RegisterForClicks("AnyUp")
	button:SetAttribute("bakunit", button:GetAttribute("unit"))

	for i, condname in ipairs(frameitem.ConditionSequence) do
		conds = conds..condname.." "..i..";"
		self:FillButtonItem(button, i, frameitem[condname])
	end

	if (frameitem[NILCONDITION]) then
		--combine conditon
		if (needcond) then
			conds = conds.." "..NILCONDITION..";"
		end

		self:FillButtonItem(button, NILCONDITION, frameitem[NILCONDITION])
	end

	if (needcond) then
		button:SetAttribute("conds", conds)
	end
end

function Header:FillButtonItem(button, condid, conditem)
	local perperfix = "cond"..condid.."-"
	local count = 0

	for _, useritem in pairs(conditem) do
		count = count + 1
		--format: cond[id]-[count]-[varname] = [varvalue]
		local perfix = perperfix..count.."-"

		button:SetAttribute(perfix.."type", useritem.Type)
		button:SetAttribute(perfix.."value", useritem.Value)
		button:SetAttribute(perfix.."target", useritem.Target)
		button:SetAttribute(perfix.."key", useritem.Key)
		button:SetAttribute(perfix.."modifier", useritem.Modifier)
		button:SetAttribute(perfix.."button", useritem.Button)
	end
end

Header.Bind = [[
	TypeValueTable = table.new()
	TypeValueTable["actionbar"] = "action"
	TypeValueTable["pet"] = "action"
	TypeValueTable["maintank"] = "action"
	TypeValueTable["mainassist"] = "action"
	TypeValueTable["click"] = "clickbutton"
	TypeValueTable["macro"] = "macrotext"

	local index = 0
	local NILCONDITION = self:GetAttribute("NILCONDITION")

	while (true) do
		index = index + 1
		local buttonname = self:GetAttribute("button"..index)

		if (not buttonname) then
			return
		end

		local button = self:GetFrameRef(buttonname)
		local conds = button:GetAttribute("conds")

		if (conds) then
			control:CallMethod("AddWatch", buttonname, conds)
		else
			control:RunAttribute("BindButton", buttonname, NILCONDITION)
		end
	end
]]

Header.BindButton = [[--arguments: buttonname, condid
	local buttonname, condid = ...
	local button = self:GetFrameRef(buttonname)

	local perperfix = "cond"..condid.."-"
	local perfix
	local count = 0

	--first clean last bindings then binding new
	local laststate = button:GetAttribute("laststate")
	if (laststate ~= nil and laststate ~= condid) then
		control:RunAttribute("UnBindButton", buttonname, laststate)
	end
	--set newstate
	button:SetAttribute("laststate", condid)

	local itemkey, itemmodifier, itembutton, itemtype, itemvalue, itemtarget, itemtypevalue

	while (true) do
		count = count + 1
		perfix = perperfix..count.."-"

		itemkey = button:GetAttribute(perfix.."key")

		--jump while loop condition
		if (not itemkey) then
			return
		end

		itemmodifier = button:GetAttribute(perfix.."modifier")
		itembutton = button:GetAttribute(perfix.."button")
		itemtype = button:GetAttribute(perfix.."type")
		itemvalue = button:GetAttribute(perfix.."value")
		itemtarget = button:GetAttribute(perfix.."target")
		itemtypevalue = TypeValueTable[itemtype] or itemtype

		--control:CallMethod("debug", button:GetName(),itemkey,itemmodifier,itembutton,itemtype,itemvalue,itemtarget,itemtypevalue)

		if (itemtarget) then
			button:SetAttribute("unit", itemtarget)
		else
			button:SetAttribute("unit", button:GetAttribute("bakunit"))
		end

		if (itembutton) then
			button:SetAttribute(itemmodifier.."type"..itembutton, itemtype)
			button:SetAttribute(itemmodifier..itemtypevalue..itembutton, itemvalue)
		else
			if (itemtype == "command") then
				button:SetBinding(true, itemkey, itemvalue)
			else
				button:SetAttribute("type", itemtype)
				button:SetAttribute(itemtypevalue, itemvalue)
				button:SetBindingClick(true, itemkey, button:GetName())
			end
		end
	end
]]

Header.UnBindButton = [[--arguments: buttonname, condid
	local buttonname, condid = ...
	local button = self:GetFrameRef(buttonname)

	local perperfix = "cond"..condid.."-"
	local perfix
	local count = 0

	local itemkey, itemmodifier, itembutton, itemtype, itemtypevalue

	while (true) do
		count = count + 1
		perfix = perperfix..count.."-"

		itemkey = button:GetAttribute(perfix.."key")

		if (not itemkey) then
			return
		end

		itemmodifier = button:GetAttribute(perfix.."modifier")
		itembutton = button:GetAttribute(perfix.."button")
		itemtype = button:GetAttribute(perfix.."type")
		itemtypevalue = TypeValueTable[itemtype] or itemtype

		if (itembutton) then
			button:SetAttribute(itemmodifier.."type"..itembutton, nil)
			button:SetAttribute(itemmodifier..itemtypevalue..itembutton, nil)
		else
			button:SetAttribute("type", nil)
			button:SetAttribute(itemtypevalue, nil)
			button:ClearBinding(itemkey)
		end
	end
]]